importScripts('pilot-pollyfill.js');
importScripts('pilotjs-api.js');
var isWorker;
try {
    isWorker = !(self instanceof SharedWorkerGlobalScope)

} catch (error) {
    // isWorker = !(self instanceof SharedWorkerGlobalScope);
    isWorker = true;
}
var ports = [];
var loginInfo = null;
var token = '';

onmessage = function (e) {
    var data = e.data;
    if (PilotUtils.isValued(data.contextClass)) {
        processContext(data);
    } else {
        throw new Error('message do not contain contextClass:' + data);
    }
}

onconnect = function (e) {
    var port = e.ports[0];

    port.addEventListener('message', function (event) {
        var data = event.data;
        if (PilotUtils.isValued(data.contextClass)) {
            processContext(data);
        } else {
            throw new Error('message do not contain contextClass:' + data);
        }
    });
    ports.push(port);
    port.start(); // Required when using addEventListener. Otherwise called implicitly by onmessage setter.

    if (PilotUtils.isValued(loginInfo)) {
        port.postMessage(loginInfo);
    }
};

var pilot = new PilotCommunicator({
    onConnect: function (event) {
        var data = {
            event: {
                data: event.data
            },
            contextClass: ContextClassType.OnPilotConnectContext
        };
        sendMessageToAllPorts(data);
    },
    onDisconnect: function (event) {
        console.log('onDisconnect', event)
        loginInfo = null;
        var data = {
            event: {
                code: event.code,
                message: event.message,
                isReconnect: event.isReconnect
            },
            contextClass: ContextClassType.OnPilotDisConnectContext
        };
        sendMessageToAllPorts(data);
    },
    onReconnectFail: function (event) {
        console.log('onReconnectFail', event)
        var data = {
            event: event,
            contextClass: ContextClassType.OnPilotReConnectFailContext
        };
        sendMessageToAllPorts(data);
    },
    onError: function (event) {
        console.log('onError', event)
        var data = {
            event: {
                code: event.code,
                message: event.message
            },
            contextClass: ContextClassType.OnPilotErrorContext
        };
        sendMessageToAllPorts(data);
    },
    onConnectFail: function (event) {
        var data = {
            event: {
                code: event.code,
                message: event.message
            },
            contextClass: ContextClassType.OnPilotConnectFailContext
        };
        sendMessageToAllPorts(data);
    },
    onNotification: function (event) {

    },
    // maxReconnectTries: 5
});

pilot._dispatchMessage = function (deferred, event) {
    pilot.heartbeatReset();
    pilot.lastHearbeatTime = new Date();
    var object;
    try {
        object = JSON.parse(event.data);
    } catch (e) {
        console.error("Error Parsing: ", event.data);
        return;
    }
    if (typeof object["data"] != "undefined" && object.data != null) {
        var data = object.data;
        var requestId = data.requestId;
        var isMarker = data.marker;
        var payload = data.payload;
        var command = data.command;
        if (data.msgType == "NOTIFICATION") {
            _onNotification(data);
            return;
        } else if (data.msgType == "HANDSHAKE_RESPONSE") {
            pilot._handleHandshake(event);
            data.contextClass = "loginInfoContext";
            data.token = token;
            loginInfo = data;
            sendMessageToAllPorts(data);
            deferred.resolve(event);
            return;
        }
        // if isMarker
        if (typeof isMarker == 'boolean' && isMarker == true) {
            _sendMessageToSWClient(data);
            return;
        }
        // if have error
        if (typeof object["errorCode"] == "string" && object.errorCode != "0") {
            _sendMessageToSWClient(object.data);
            return;
        }
        _sendMessageToSWClient(data);
    } else {

    }

}

function _handleHandshake(data) {
    loginInfo = data;
    loginInfo.contextClass = "loginInfoContext";
    sendMessageToAllPorts(loginInfo);
}

function processContext(data) {
    var context = data.contextClass;
    switch (data.contextClass) {
        case ContextClassType.LoginToPilotContext:
            var params = data.loginParam;
            pilot.login(params.url, params.username, params.password, params.authnType, params.lifeTime).then(function (response) {
                var loginResponseContext = {
                    contextClass: ContextClassType.LoginToPilotContext,
                    loginResponse: response
                }
                sendMessageToAllPorts(loginResponseContext);
            }).catch(function (status, responseText) {
                var loginResponseContext = {
                    contextClass: ContextClassType.LoginToPilotContext,
                    error: status
                }
                sendMessageToAllPorts(loginResponseContext);
            })
            break;
        case ContextClassType.PilotFuncInvokeContext:
            var methodName = data.methodName;
            var arguments = data.arguments;
            var pilotFuncResult;
            var pilotFuncResultP;
            try {
                var result = pilot[methodName].apply(pilot, arguments);
                if (result instanceof Promise) {
                    pilotFuncResultP = result.then(function (res) {
                        pilotFuncResult = {
                            contextClass: ContextClassType.PilotFuncResultContext,
                            result: res,
                            uuid: data.uuid
                        };
                        return Promise.resolve(pilotFuncResult);
                    });
                } else {
                    pilotFuncResult = {
                        contextClass: ContextClassType.PilotFuncResultContext,
                        result: result,
                        uuid: data.uuid
                    };
                    pilotFuncResultP = Promise.resolve(pilotFuncResult);
                }


            } catch (e) {
                pilotFuncResult = {
                    contextClass: ContextClassType.PilotFuncResultContext,
                    error: e.message,
                    uuid: data.uuid
                };
                pilotFuncResultP = Promise.resolve(pilotFuncResult);
            }
            pilotFuncResultP.then(function (res) {
                sendMessageToAllPorts(res);
            });
            break;
        case ContextClassType.ConnectToPilot:
            if (!isConnected()) {
                token = data.token;
                pilot.connect(data.url, data.token, true).catch(function (e) {
                    console.error(e);
                });
            } else {
                console.info('already connectToPilot');
            }
            break;
        case ContextClassType.QNSContext:
            _sendMessageToPilot(data);
            if (data.command == CommandType.CommandTypeOnlySubscribe || data.command == CommandType.CommandTypeQueryAndSubScribe) {
                pilot._subscriptionMap[data.requestId] = data;
            }
            break;
        case ContextClassType.ProxyInvokeContext:
            _sendMessageToPilot(data);
            break;
        case ContextClassType.CancelSubCommandContext:
            _sendMessageToPilot(data);
            delete pilot._subscriptionMap[data.requestId];
            break;
        case ContextClassType.DisconnectToPilotContext:
            if (isConnected()) {
                pilot.disconnect();
            } else {
                console.info('already disconnectToPilot');
            }
        default:
            _sendMessageToPilot(data);
            break;
    }
}

function isConnected() {
    if (pilot._webSocket == null) return false;
    if (pilot._webSocket.readyState != WebSocket.OPEN) return false;
    return true;
}

function sendMessageToAllPorts(data) {
    if (isWorker) {
        self.postMessage(data);
    } else {
        ports.forEach(function (port) {
            port.postMessage(data);
        });
    }
}

function _sendMessageToSWClient(data) {
    if (isWorker) {
        self.postMessage(data);
    } else {
        ports.forEach(function (port) {
            port.postMessage(data);
        });
    }
}

function _sendMessageToPilot(object) {
    if (isConnected()) {
        // webSocket.send(JSON.stringify(object));
        pilot._sendObject(object, true);
        console.log('===============_sendMessage', JSON.stringify(object));
    } else {
        // qnsBuffers = qnsBuffers.concat(object);
    }
}